package action;

import game.GameState;
import character.MyCharacter;
import board.BoardUtil;
import board.Tile;
import character.CharacterSize;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import game.DataStore;
import game.DefaultValues;
import game.StateSwitcher;
import misc.Vector3i;

public class ActionMove extends Action {
    protected Vector3i boardDestination;
    protected Vector3f worldDestination;
    protected int ticksRemainingToMoveLocation;

    @Deprecated
    protected ActionMove() {}
    
    public ActionMove(MyCharacter character, Vector3i destination) {
        super(character, character.getCharacterStats().getMoveSpeedNoModifier());
        boardDestination = destination;
	translateBoardDestination();
        if(BoardUtil.tilesBetweenManhattan(character.getQueuedLocation(), boardDestination) > 1) {
	    setTotalTicks(character.getCharacterStats().getDiagonalMoveSpeedNoModifier());
	}
        worldDestination = BoardUtil.boardToWorld(boardDestination);
        translateWorldDestination();
    }

    public ActionMove(MyCharacter character, Vector3f destination) {
        super(character, -1);
        worldDestination = destination;
        translateWorldDestination();
    }

    private void translateBoardDestination() {
	if(character.getCharacterSettings().getCharacterSize() == CharacterSize.DOUBLE) {
	    if(boardDestination.getZ() > character.getQueuedLocation().getZ()) {
		boardDestination = boardDestination.clone().addZ(-1);
	    }
	} else if(character.getCharacterSettings().getCharacterSize() == CharacterSize.FOUR){
	    if(boardDestination.getZ() > character.getQueuedLocation().getZ()) {
		if(boardDestination.getX() > character.getQueuedLocation().getX()) {
		    boardDestination = boardDestination.clone().addX(-1).addZ(-1);
		} else {
		    boardDestination = boardDestination.clone().addZ(-1);
		}
	    } else if (boardDestination.getX() > character.getQueuedLocation().getX()) {
		boardDestination = boardDestination.clone().addX(-1);
	    }
	}
    }
    
    private void translateWorldDestination() {
        worldDestination = worldDestination.add(0f, Tile.HEIGHT/2+MyCharacter.HEIGHT/2, 0f);
    }

    @Override
    protected void start() {
	if(boardDestination != null) {
	    ticksRemainingToMoveLocation = Math.round(FastMath.floor((float)getTotalTicks()/2));
	    DataStore.board.characterIntendsToMove(character, boardDestination);
	}
        updateViewDir();
    }
    
    @Override
    protected boolean tick() {
        if(StateSwitcher.getGameState() == GameState.ROAM)
	    return tickRoam();
	else if(StateSwitcher.getGameState() == GameState.COMBAT)
	    return tickCombat();
	return true;
    }

    protected boolean tickRoam() {
        character.setBoardLocation(BoardUtil.castDownToBoard(charControl.getPhysicsLocation()));
        if(charControl.getPhysicsLocation().distance(worldDestination) < DefaultValues.ACTION_MOVE_STOP_DISTANCE_THRESHOLD) {
            completeAction();
        } else {
            charControl.setWalk(worldDestination, character.getCharacterStats().getMoveSpeedWithModifier()/(DataStore.TICK_TO_MOVE_SPEED_FACTOR/DataStore.TIME_PER_TICK)); //not sure if this is a valid formula whatsoever
        }
        return true;
    }

    protected boolean tickCombat() {
	float distanceLeft = charControl.getPhysicsLocation().distance(worldDestination);
        float speedReq = (distanceLeft/ticksRemaining)/DataStore.TIME_PER_TICK;
        charControl.setWalk(worldDestination, speedReq/DataStore.TICK_TO_MOVE_SPEED_FACTOR);

        if(ticksRemaining-1 == ticksRemainingToMoveLocation)
            character.moveLocation(boardDestination);

        return true;
    }
    
    @Override
    protected void complete() {
        charControl.stopWalking();
    }

    @Override
    protected void abort() {
        charControl.stopWalking();
    }
    
    @Override
    public void pause() {
        charControl.stopWalking();
    }
    
    @Override
    public void unpause() {}
    
    protected void updateViewDir() {
        Vector3f viewDir = worldDestination.subtract(charControl.getPhysicsLocation());
        viewDir.multLocal(1f, 0f, 1f);
        charControl.setViewDirection(viewDir);
    }
}
